'use client'; import './style.scss'; import 'animate.css'; import { use, useEffect, useState } from 'react'; import { useDonationAlert } from '@/hooks/useDonationAlert'; import { DonationAlertConfig } from '@/types/donation'; import { fetchApi } from '@/lib/utils/client'; import View from './view'; type Props = { params: Promise<{ widgetToken: string }>; }; const DEFAULT_CONFIG: DonationAlertConfig = { id: 0, title: '', amount: 0, matchType: 0, message: '{이름}님이 {금액}을 후원해주셨습니다!', playDelaySec: 0, displayDurationSec: 10, popupEffect: 'fadeIn', textEffect: null, nicknameFontFamily: null, nicknameFontSize: 24, nicknameFontColor: '#FFD700', amountFontFamily: null, amountFontSize: 24, amountFontColor: '#FF6B35', messageFontFamily: null, messageFontSize: 18, messageFontColor: '#FFFFFF', templateFontFamily: null, templateFontSize: 24, templateFontColor: '#FFFFFF', enableImage: true, imageUrl: '/resources/donate-default-image.gif', enableSound: true, soundUrl: '/sounds/default-donate-effect.mp3', isActive: true }; function matchConfig(configs: DonationAlertConfig[], amount: number): DonationAlertConfig { // 1순위: Exact 매칭 (MatchType === 1) const exact = configs.find(c => c.matchType === 1 && c.amount === amount && c.isActive); if (exact) { return exact; } // 2순위: MinThreshold (MatchType === 0) — 금액 이상 중 가장 높은 것 const thresholds = configs .filter(c => c.matchType === 0 && c.amount <= amount && c.isActive) .sort((a, b) => b.amount - a.amount); return thresholds[0] ?? DEFAULT_CONFIG; } export default function AlertPage({ params }: Props) { const { widgetToken } = use(params); const hubUrl = process.env.NEXT_PUBLIC_API_URL + '/hubs/donation'; const [configs, setConfigs] = useState([]); const { current, remoteState, onAlertComplete } = useDonationAlert( widgetToken, hubUrl, // 위젯이 실제 재생할 displayDurationSec 을 리모콘 타이머용으로 hub 에 동봉 (alert) => matchConfig(configs, alert.amount).displayDurationSec ); // API에서 config 목록 로드 useEffect(() => { fetchApi<{ list: DonationAlertConfig[] }>(`/api/widget/alert/config/${widgetToken}`, { silent: true }).then(res => { if (res.success && res.data?.list) { setConfigs(res.data.list); } }).catch(() => {}); }, [widgetToken]); const config = current ? matchConfig(configs, current.amount) : null; return (
{current && config && ( )}
); }